package gpar.ep;

import gpar.Program; 
import gpar.Settings;
import gpar.ep.*;

import java.util.Hashtable;
import java.util.List;
import java.util.ArrayList;

/** Representing a sort of BNF grammar which can be used within methods for bots. Grammar needs to represent 
% the following <br />
* < <ul>
* <li> A way to output the representing string
* <li> A way to mutate to different expressions
* </ul>
* TODO: implement `variable assignment'
*/
public class Grammar implements Expressionable
{

    /** The grammar above this one, the parent grammar. */
    protected Grammar parent;
    /** The String which represents this grammar. */
    protected String grammarRepresentation; 

    protected String before, middle, after; 
    protected Expressionable[] expressionables; 

 


    /** Can be used to create a grammar. */
    public Grammar (String inRepresentation, Grammar parent)
    {
        before = middle = after = "";
        for (Expressionable e : expressionables)
            e = new EmptyExpressionable();

        this.grammarRepresentation = grammarRepresentation;
        this.parent = parent;
    
        // input example: "statements"- [["statement", "statements", "statement"]] 
        // extract the options, thus: [["statement", "statements", "statement"]] 
        List<List<String>> options = Settings.grammarHash.get(inRepresentation);
        int optionsPick = Program.random.nextInt(options.size());
        // extract the correct option, thus: ["statement", "statements", "statement"]
        List<String> expendables = options.get(optionsPick);

        // if there is only one option we need to examinate it
        if (expendables.size() == 1)
        {
            int expendablesPick = Program.random.nextInt(expendables.size());
            String[] finalPick = expendables.get(expendablesPick).split("-"); 
      
            // if finalPick.length > 1 it means that there was a -, which means something
            // special is going on!
            if (finalPick.length > 1)
            {
                // from the current entry level (inRepresentation) we could check what kind
                // of grammar should be created and traceback from there, but now the
                // TERMINAL identifier identifies more than just that its terminal; it 
                // identifies what kind of grammar we could expect!
                before = finalPick[0];
                //if (finalPick[1].equals("TERMINAL0")) // <- unnecessary 
                if (finalPick[1].equals("TERMINAL1")) // for now this is argumentRequiring1
                {
                    expressionables[9] = new ExpressionTree();
                    middle = ");";
                }
                else if (finalPick[1].equals("NONTERMINAL0")) // for now this is else
                {
                    expressionables[0] = new Grammar("statements", this);
                    middle = "}";
                }
                else if (finalPick[1].equals("NONTERMINAL1")) // for now this is if,elseif,while
                {
                    expressionables[0] = new ExpressionTree();
                    middle = "){";
                    expressionables[1] = new Grammar("statements", this);  
                    after = "}";
                }
            }       
            // otherwise we just continue with expanding the grammar
            else
                expressionables[0] = new Grammar(finalPick[0], this);
        }
        // otherwise, we have several childs!
        else  // TODO: built in a failsafe here ...
            for (int i = 0; i < expendables.size(); i ++)
                expressionables[i] = new Grammar(expendables.get(i), this);
    }

    /** Mutates the grammar or an expression(Tree) in the grammar. Altering the grammar
    * can be done like so: 
    * <ul>
    * <li> A different rule is used. A rule such as `statement :- argumentRequiring0 
    * (including the rest, filled in below/after argumentRequiring0)' is altered to a 
    * different a rule e.g. `statement :- //'. This could be done anywhere but high
    * up can mean a gigantic mutation. </li>
    * </ul>
    * No statement can end in a non-non-terminal, it is always filled out somehow. 
    * (Should 'statement :- //' be used as default?). 
    */
    public void mutate ()
    {

    }

    public String output()
    {
        return before + expressionables[0].output() + middle +
            expressionables[1].output() + after + expressionables[2];
    }



    //////////// public properties {{{

    public Grammar getParent()
    {
        return parent;
    }   
    
    public String getGrammarRepresentation()
    {
        return grammarRepresentation;
    }

    // }}}


}


